/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.opu.db_vdumper.ui.component;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * AbsoluteLayout is a LayoutManager that works as a replacement for
 * "null" layout to allow placement of components in absolute positions.
 * @see PDimension
 * @author Potochnak Yana
 */
public class AbsoluteLayout implements LayoutManager2, Serializable {

    /** A mapping &lt;Component, AbsoluteConstraints> */
    protected Map<Component, PDimension> constraints = new HashMap<Component, PDimension>();

    /**
     *  Adds the specified component with the specified name to the layout.<br>
     *  <b>Note:</b> Olways throws IllegalArgumentException.
     * @param name the component name
     * @param comp the component to be added
     */
    @Override
    public void addLayoutComponent(String name, Component comp) {
        throw new IllegalArgumentException();
    }

    /**
     * Removes the specified component from the layout.
     * @param comp the component to be removed
     */
    @Override
    public void removeLayoutComponent(Component comp) {
        constraints.remove(comp);
    }

    /**
     * Calculates the preferred dimension for the specified
     * panel given the components in the specified parent container.
     * @param parent the component to be laid out
     * @see #minimumLayoutSize
     */
    @Override
    public Dimension preferredLayoutSize(Container parent) {
        int maxWidth = 0;
        int maxHeight = 0;
        for (Component comp : constraints.keySet()) {
            PDimension ac = constraints.get(comp);
            Dimension size = comp.getPreferredSize();

            int width = ac.getWidth();
            if (width == -1) {
                width = size.width;
            }
            int height = ac.getHeight();
            if (height == -1) {
                height = size.height;
            }

            if (ac.getX() + width > maxWidth) {
                maxWidth = ac.getX() + width;
            }
            if (ac.getY() + height > maxHeight) {
                maxHeight = ac.getY() + height;
            }
        }
        return new Dimension(maxWidth, maxHeight);
    }

    /**
     * Calculates the minimum dimension for the specified
     * panel given the components in the specified parent container.
     * @param parent the component to be laid out
     * @see #preferredLayoutSize
     */
    @Override
    public Dimension minimumLayoutSize(Container parent) {
        int maxWidth = 0;
        int maxHeight = 0;
        for (Component comp : constraints.keySet()) {
            PDimension ac = constraints.get(comp);

            Dimension size = getMinimumComponentSize(comp);

            int width = ac.getWidth();
            if (width == -1) {
                width = size.width;
            }
            int height = ac.getHeight();
            if (height == -1) {
                height = size.height;
            }

            if (ac.getX() + width > maxWidth) {
                maxWidth = ac.getX() + width;
            }
            if (ac.getY() + height > maxHeight) {
                maxHeight = ac.getY() + height;
            }
        }
        return new Dimension(maxWidth, maxHeight);
    }

    /**
     *  Return minimum size of the component
     * @param comp component whose size is determined
     * @return minimum size of the component
     */
    protected Dimension getMinimumComponentSize(Component comp) {
        return comp.getMinimumSize();
    }

    /**
     * Lays out the container in the specified panel.
     * @param parent the component which needs to be laid out
     */
    @Override
    public void layoutContainer(Container parent) {
        for (Component comp : constraints.keySet()) {
            PDimension ac = constraints.get(comp);
            Dimension size = comp.getPreferredSize();

            int width = ac.getWidth();
            if (width == -1) {
                width = size.width;
            }
            int height = ac.getHeight();
            if (height == -1) {
                height = size.height;
            }

            comp.setBounds(ac.getX(), ac.getY(), width, height);
        }
    }

    /**
     * Adds the specified component to the layout, using the specified
     * constraint object.
     * @param comp the component to be added
     * @param constr  where/how the component is added to the layout.
     */
    @Override
    public void addLayoutComponent(Component comp, Object constr) {
        if (!(constr instanceof PDimension)) {
            throw new IllegalArgumentException();
        }
        constraints.put(comp, (PDimension) constr);
    }

    /**
     * Returns the maximum size of this component.
     * @see java.awt.Component#getMinimumSize()
     * @see java.awt.Component#getPreferredSize()
     * @see LayoutManager
     */
    @Override
    public Dimension maximumLayoutSize(Container target) {
        return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
    }

    /**
     * Returns the alignment along the x axis.  This specifies how
     * the component would like to be aligned relative to other
     * components.  The value should be a number between 0 and 1
     * where 0 represents alignment along the origin, 1 is aligned
     * the furthest away from the origin, 0.5 is centered, etc.
     */
    @Override
    public float getLayoutAlignmentX(Container target) {
        return 0;
    }

    /**
     * Returns the alignment along the y axis.  This specifies how
     * the component would like to be aligned relative to other
     * components.  The value should be a number between 0 and 1
     * where 0 represents alignment along the origin, 1 is aligned
     * the furthest away from the origin, 0.5 is centered, etc.
     */
    @Override
    public float getLayoutAlignmentY(Container target) {
        return 0;
    }

    /**
     * Invalidates the layout, indicating that if the layout manager
     * has cached information it should be discarded.
     */
    @Override
    public void invalidateLayout(Container target) {
    }
}
